﻿using System;
using System.Linq;
using ITTestingSystem.BusinessLogic.DataServices.Abstract;
using ITTestingSystem.BusinessLogic.DataServices.Concrete;
using ITTestingSystem.BusinessLogic.UnitTests.AdditionalClasses;
using ITTestingSystem.Domain.Entities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace ITTestingSystem.BusinessLogic.UnitTests
{
    [TestClass]
    public class BaseServiceTests
    {
        [TestMethod]
        public void ShouldAddEntity()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            var user = new User();

            service.Add(user);

            Assert.IsTrue(repository.GetById(0) == user);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ShouldThrowArgumentNullException()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            service.Add(null);
        }

        [TestMethod]
        public void ShouldReturnAllEntities()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            Assert.AreEqual(repository.GetAll().Count(), service.GetAll().Count());

            var user = new User();
            repository.Add(user);

            Assert.AreEqual(repository.GetAll().Count(), service.GetAll().Count());
        }

        [TestMethod]
        public void ShouldReturnEntityById()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            var user = new User();
            repository.Add(user);

            var actual = service.GetById(0);

            Assert.AreEqual(actual, user);
        }

        [TestMethod]
        public void ShouldReturnNull()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            var actual = service.GetById(0);

            Assert.AreEqual(actual, null);
        }

        [TestMethod]
        public void ShouldUpdateEntity()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            var user = new User { FirstName = "FirstName" };

            repository.Add(user);

            user.FirstName = "First";

            service.Update(user);

            var updatedUserInRepository = service.GetById(0);

            Assert.AreEqual(user.FirstName, updatedUserInRepository.FirstName);
        }

        [TestMethod]
        public void ShouldNotThowExceptionWhenUpdateEntity()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            service.Update(new User());
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ShouldThrowArgumentNullExceptionWhenUpdateEntity()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            service.Update(null);
        }

        [TestMethod]
        public void ShouldDeleteEntityById()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            var user = new User { FirstName = "FirstName" };

            repository.Add(user);

            service.DeleteById(0);

            Assert.AreEqual(repository.GetAll().Count(), service.GetAll().Count());
        }

        [TestMethod]
        public void ShouldNotThrowExceptionWhenDeleteById()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            service.DeleteById(1);
        }

        [TestMethod]
        public void ShouldDeleteEntity()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            var user = new User { Id = 5 };

            // Count == 1
            repository.Add(user);

            // count should == 0
            service.Delete(user);

            Assert.AreEqual(repository.GetAll().Count(), 0);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ShouldThrowArgumentNullExceptionWhenDeleteEntity()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            service.Delete(null);
        }

        [TestMethod]
        public void ShouldNotThrowExceptionWhenDeleteEntity()
        {
            // Now is empty
            var repository = new MockRepository<User>();
            var service = new BaseService<User>(repository) as IBaseService<User>;

            service.Delete(new User());
        }

        [TestMethod]
        public void ShouldCallsSaveAfterAddEntity()
        {
            var mockRepository = new Mock<IRepositoryForEntity<User>>();

            var service = new BaseService<User>(mockRepository.Object) as IBaseService<User>;
            service.Add(new User());

            mockRepository.Verify(mock => mock.Add(It.IsAny<User>()));
            mockRepository.Verify(mock => mock.Save());
        }

        [TestMethod]
        public void ShouldCallsSaveAfterUpdateEntity()
        {
            var mockRepository = new Mock<IRepositoryForEntity<User>>();

            var service = new BaseService<User>(mockRepository.Object) as IBaseService<User>;
            service.Update(new User());

            mockRepository.Verify(mock => mock.Update(It.IsAny<User>()));
            mockRepository.Verify(mock => mock.Save());
        }

        [TestMethod]
        public void ShouldCallsSaveAfterDeleteEntity()
        {
            var mockRepository = new Mock<IRepositoryForEntity<User>>();

            var service = new BaseService<User>(mockRepository.Object) as IBaseService<User>;
            service.Delete(new User());

            mockRepository.Verify(mock => mock.Delete(It.IsAny<User>()));
            mockRepository.Verify(mock => mock.Save());

            service.DeleteById(1);
            mockRepository.Verify(mock => mock.DeleteById(It.IsAny<int>()));
            mockRepository.Verify(mock => mock.Save());
        }
    }
}
